package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;

    @Autowired
    private TrackStatMapper trackStatMapper;
    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private VodService vodService;
    @Autowired
    private AlbumInfoService albumInfoService;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        try {
            TrackInfo trackInfo = new TrackInfo();
//        从前端传的声音信息Vo里拷贝属性值传到trackInfo里存到数据库
            BeanUtils.copyProperties(trackInfoVo,trackInfo);
//        赋值用户id：
            trackInfo.setUserId(userId);
//        保存该声音的序号(查询专辑包含声音的总数+1)
            AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
            trackInfo.setOrderNum(albumInfo.getIncludeTrackCount()+1); //IncludeTrackCount是个属性，表示该专辑包含声音总数
//        处理流媒体的数据：时长/类型这些数据页面没传递，可以从腾讯云查询流媒体数据，然后赋值保存进我们数据库
            TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());

//        赋值：
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
//        保存声音结束
            trackInfoMapper.insert(trackInfo);

//        保存声音状态数据：
            saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
            saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_COLLECT);
            saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_PRAISE);
            saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_COMMENT);

//        保存声音序号：
            albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()+1);
            albumInfoMapper.updateById(albumInfo);
        } catch (BeansException e) {
            log.error("保存声音信息失败：{}",e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public IPage<TrackListVo> findUserTrackPage(Page<TrackInfoVo> trackInfoVoPage, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.selectUserTrackPage(trackInfoVoPage,trackInfoQuery);
    }


    /**
     * 删除声音（根据id）
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeTrackInfo(Long id) {
//       1.现根据声音id获取声音信息(这里的this就是TrackInfoServiceImpl实体对象，
//       通过调用它的实例对象调用getById()方法。
        TrackInfo trackInfo = this.getById(id);
//        2.删除该id专辑的信息
        this.removeById(id);
//        3.更新此声音所属专辑的声音总数
//        ①获取此声音所属专辑信息
        AlbumInfo albumInfo = this.albumInfoService.getById(trackInfo.getAlbumId());
//        ②更新此声音所属专辑的声音总数
        int includeTrackCount = albumInfo.getIncludeTrackCount() - 1;
//        ③把新专辑声音总数重设置进专辑信息
        albumInfo.setIncludeTrackCount(includeTrackCount);
//        ④重新更新该声音id所属专辑信息
        albumInfoService.updateById(albumInfo);
//        4.删除该声音id的统计数据
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId,id));
//        5.重新更新声音序号(参数1：该声音所属专辑；参数2：该声音序号)
        trackInfoMapper.updateTrackNum(trackInfo.getAlbumId(),trackInfo.getOrderNum());
//        6.删除腾讯云平台该声音媒体(从该声音信息中获取流媒体id，再用腾讯云删除）
        vodService.removeTrack(trackInfo.getMediaFileId());

    }


    /**
     * 更新声音信息
     */
    @Override
    public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {
//        1.获取这个id下的原始声音对象
        TrackInfo trackInfo = this.getById(id);
//        2.获取原始声音对象的fileId
        String mediaFileId = trackInfo.getMediaFileId();
//        3.进行属性拷贝
        BeanUtils.copyProperties(trackInfoVo,trackInfo);
//        4.获取声音信息，页面传递的fileId与数据库的fileId不相等说明声音文件是新的，修改
        if (!trackInfoVo.getMediaFileId().equals(mediaFileId)){
//            从腾讯云里找出新声音文件的流媒体文件信息
            TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
//            判断其流媒体文件信息是否为空
            if (null == trackMediaInfoVo){
//                流媒体文件为空，就抛出异常
                throw new GuiguException(ResultCodeEnum.VOD_FILE_ID_ERROR);
            }
//            如果不为空，就往原始声音对象信息里设置新的流媒体文件信息
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
            trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());

//            删除云点播里面的旧声音数据
            vodService.removeTrack(mediaFileId);
        }
//        更新声音信息数据
        this.updateById(trackInfo);

    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> pageParam, Long albumId, Long userId) {
//        思路：根据专辑id获取到声音列表，将数据封装到AlbumTrackListVo中返回给前端。
//        当用户id为空时，把试听集数以外的声音标上付费标识；
//        当用户id存在时，要判断专辑的支付类型。如果专辑是vip免费，要判断该user是不是vip
//        再对比用户购买的专辑和声音id，如果用户买过了，也显示不用付费。

//        1.先根据专辑id获取声音集合：
        IPage<AlbumTrackListVo> pageInfo = trackInfoMapper.selectAlbumTrackPage(pageParam,albumId);
//        2.查到专辑信息，以判断用户是否需要付费
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        Assert.notNull(albumInfo,"专辑对象不能为空！");

//        3.判断用户是否登录
        if (null == userId){
//            ①如果用户没有登录(即此处没有userId)，那么除了免费的专辑，都需要显示付费标识
            if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())){
//                处理试听声音，获取需要付费的声音列表,把序号大于免费试听集数的声音列单拎出来：
                List<AlbumTrackListVo> albumTrackNeedPaidListVoList = pageInfo.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum().intValue() > albumInfo.getTracksForFree())
                        .collect(Collectors.toList());

                if (!CollectionUtils.isEmpty(albumTrackNeedPaidListVoList)){
                    albumTrackNeedPaidListVoList.forEach(albumTrackListVo -> {
//                  如果需要付费声音列表不为空，遍历每个声音，把展示付费标识设置为true
                        albumTrackListVo.setIsShowPaidMark(true);
                    });
                }
            }
        }else {
//            用户已登录
    //       如果专辑的类型是vip免费,开始查用户是不是vip
                Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(userId);
                Assert.notNull(userInfoVoResult,"用户信息不能为空！");
                UserInfoVo userInfoVo = userInfoVoResult.getData();
                Assert.notNull(userInfoVo,"查询用户信息失败。");
                //            声明变量是否需要付费，默认不需要
                boolean isNeedPaid = false;
//                判断专辑的类型：
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())){
//                ①第一种：用户不是vip + 虽是vip但瞬间过期了，照样掏钱！
                if ((userInfoVo.getIsVip() == 1 && userInfoVo.getVipExpireTime().before(new Date())) || userInfoVo.getIsVip() == 0){
                    isNeedPaid = true;
                }
            }else  if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())){
//                最后，专辑本身反正就是需要你掏钱的情况：
                isNeedPaid = true;
            }else{
                isNeedPaid = false;
            }

//            4.统一处理付费声音列表，这里再度把他们单拎出来成集合
            if (isNeedPaid){
//                需要知道用户购买了哪些声音，专辑id：
                List<AlbumTrackListVo> albumTrackNeedPaidListVoList = pageInfo.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum().intValue() > albumInfo.getTracksForFree()).collect(Collectors.toList());
//                    根据付费专辑列表VO获取付费声音id合集，用来判断用户是不是买过专辑或者该声音了：
                    List<Long> trackIdList = albumTrackNeedPaidListVoList.stream().map(AlbumTrackListVo::getTrackId).collect(Collectors.toList());
//                    再获取用户购买过的声音id列表，以比较二者:
                    Result<Map<Long, Integer>> mapResult = userInfoFeignClient.userIsPaidTrack(albumId,trackIdList);//这个方法返回声音id（key）和是否已购（value）的map
                    Assert.notNull(mapResult,"查询用户购买声音失败！");
                    Map<Long, Integer> map = mapResult.getData(); //获取用户购买过的声音合集map
                for (AlbumTrackListVo albumTrackListVo : albumTrackNeedPaidListVoList) {
                    albumTrackListVo.setIsShowPaidMark(map.get(albumTrackListVo.getTrackId()) == 0);
                }
                    };
                }

        return pageInfo;
    }

    @Override
    public void updateStat(Long albumId, Long trackId, String statType, Integer count) {
//        1.更新声音播放量
        trackInfoMapper.updateStat(trackId,statType,count);
//        2.更新专辑播放量
        if (statType.equals(SystemConstant.TRACK_STAT_PLAY)){
            albumInfoService.updateStat(albumId,SystemConstant.ALBUM_STAT_PLAY,count);
        }
    }

    @Override
    public void updateTrackStat(TrackStatMqVo trackStatMqVo) {
//        1.先判断传进来的数据是否属于声音播放量
        if (SystemConstant.TRACK_STAT_PLAY.equals(trackStatMqVo.getStatType())){
//            2.调用更新方法
            trackInfoMapper.updateTrackStat(trackStatMqVo.getCount(),trackStatMqVo.getTrackId(),trackStatMqVo.getStatType());
//          3.更新专辑播放量
            albumInfoMapper.updateAlbumStat(trackStatMqVo.getCount(),trackStatMqVo.getAlbumId(),SystemConstant.ALBUM_STAT_PLAY);
        }else if (SystemConstant.TRACK_STAT_COLLECT.equals(trackStatMqVo.getStatType())){
//            暂无
        }
    }

    /**
     * 保存声音统计数据
     *
     */
    public void saveTrackStat(Long trackId, String statPlay) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statPlay);
        trackStat.setStatNum(new Random().nextInt(1000));
        trackStatMapper.insert(trackStat);



    }
}
